<template>
	<div class=" pmenu">
		<div id="container" />
		<div :class="{ 'n-dialog': 1, 'n-dialogShow': showConf }">
			<!-- <i class="n-dialog-switch el-icon-setting" @click="showConf = !showConf"></i> -->
			<el-icon class="n-dialog-switch icon-right" @click="showConf = !showConf">
				<Setting />
			</el-icon>
			<div class="n-dialog-content">
				<h3>当前模式</h3>
				<div>
					<el-radio v-model="mode" label="def">信息读取</el-radio>
					<el-radio v-model="mode" label="mark">站点设计</el-radio>
					<el-radio v-model="mode" label="line">铺设管道</el-radio>
					<el-radio v-model="mode" label="drag">站点移动</el-radio>
				</div>
				<template v-if="mode === 'mark'">
					<h3>站点类型</h3>
					<div>
						<el-radio v-model="markConf.type" label="def">默认</el-radio>
						<el-radio v-model="markConf.type" label="red">特殊站</el-radio>
					</div>
				</template>
				<h3>定位</h3>
				<el-input v-model="latitude" placeholder="纬度"
					style="width: 100px; margin-right: 10px; margin-top: 10px;" />
				<el-input v-model="longitude" placeholder="经度" style="width: 100px; margin-top: 10px;" />
				<el-button size="mini" round @click="searchfix"
					style="color: #000; margin-left: 10px; margin-top: 10px;">定位</el-button>
				<el-button size="mini" round @click="search" style="color: #000; margin-top: 10px;">查找</el-button>

				<h3>参数</h3>
				<div class="n-form">
					<p>请输入年输量(×10⁸ m³)：</p>
					<el-input v-model="params.a" />
					<p>请输入年工作天数(天)：</p>
					<el-input v-model="params.b" />
					<p>请输入管道直径(m)：</p>
					<el-input v-model="params.d" />
					<p>请输入管道壁厚(m)：</p>
					<el-input v-model="params.e" />
					<p>请输入天然气温度(K)：</p>
					<el-input v-model="params.g" />
					<p>请输入天然气相对密度：</p>
					<el-input v-model="params.h" />
					<p>请输入出站温度(K)：</p>
					<el-input v-model="params.a2" />
					<p>请输入压缩因子：</p>
					<el-input v-model="params.i" />
					<p>请输入水力摩阻系数：</p>
					<el-input v-model="params.m" />
					<el-button plain type="primary"
						@click="handleClickAndClear($event, ['a', 'b', 'd', 'e', 'g', 'h', 'a2', 'i', 'm'])">清零</el-button>
					<el-button plain type="primary" @click="save">存储</el-button>
					<el-button plain type="primary" @click="handleClickAndShow">编辑</el-button>
				</div>

			</div>
		</div>
		<el-dialog title="项目列表" v-model="listConf.show">
			<div class="pcomputed-dialog">
				<h3><el-button type="primary" @click="add" plain>新增项目</el-button></h3>
				<ul>
					<li v-for="item in filteredList" :key="item.id">
						<i>{{ filteredList.indexOf(item) + 1 }}</i>
						{{ item.name }}
						<el-button type="primary" @click="check(item)" link>编辑</el-button>
						<el-button type="danger" @click="del(item)" link>删除</el-button>
					</li>
				</ul>
			</div>
		</el-dialog>
	</div>
</template>
<script>
import AMapLoader from "@amap/amap-jsapi-loader"


export default {
	name: "index",
	data() {
		window.vm = this
		return {
			listConf: {
				show: true,
				list: [
					{
						id: null,
						name: '',
						a: '',   //年输量
						b: '',   //年工作天数
						d: '',   //管道直径
						e: '',   //管道壁厚
						g: '',   //天然气温度
						h: '',   //天然气相对密度
						i: '',   //压缩因子
						m: '',   //摩阻系数					
						a2: '',	 //出站温度
					},
				],
			},
			params: {
				id: null,
				name: '',
				a: '',   //年输量
				b: '',   //年工作天数
				d: '',   //管道直径
				e: '',   //管道壁厚
				g: '',   //天然气温度
				h: '',   //天然气相对密度
				i: '',   //压缩因子
				m: '',   //摩阻系数					
				a2: '',	 //出站温度
			},
			showConf: true,
			//初始化 map 对象
			//实时屏幕高度
			windowHeight: document.documentElement.clientHeight,
			longitude: null,
			latitude: null,
			mode: "mark",
			markType: 'def',
			markConf: {
				type: 'def',			//节点类型
				img: {
					// 节点类型的图片配置， 默认不需要提供
					'def': () => null,
					'red': () => ({
						icon: new AMap.Icon({
							image: 'http://a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-red.png',
							size: new AMap.Size(22, 36),
							imageSize: new AMap.Size(22, 36),
						}),
						offset: new AMap.Pixel(-11, -32),
					})
				}
			},
		}
	},
	created() {
		this.load()
	},
	computed: {
		filteredList() {
			const username = this.$store.state.userInfo.username;
			return this.listConf.list.filter(item => item.username === username);
		}
	},
	mounted() {
		// 这些不需要响应式，不需要放data里，不然卡顿
		this.i = 0
		this.markers = []
		this.curLine = null
		this.map = null
		this.infoWin = null
		this.lines = []

		//DOM初始化完成进行地图初始化
		this.initMap()
		// 当浏览器被重置大小时执行
		window.onresize = () => {
			return (() => {
				this.windowHeight = document.documentElement.clientHeight
			})()
		}

		this.setDrag()
	},
	watch: {
		mode() {
			this.setDrag()
		}
	},
	beforeUnmount() {
		this.exitsave(); // 在组件销毁前调用save方法  
		location.reload();
	},
	methods: {
		load() {
			this.$request.get("/computed", {
				params: {
					id: this.id,
					username: this.username,
					name: this.name,
					a: this.a,
					b: this.b,
					d: this.d,
					e: this.e,
					f: this.f,
					g: this.g,
					h: this.h,
					i: this.i,
					m: this.m,
					a2: this.a2,
				}
			}).then(res => {
				this.listConf.list = res
			})
		},
		// 设置拖拽
		setDrag() {
			this.markers.forEach((m) => m.setDraggable(this.mode === "drag"))
		},
		bindEv() {
			const { map } = this
			map.on("click", (e) => {
				this.addMark(e.lnglat)
			})
		},
		// 2点距离
		getDis(lat1, lon1, lat2, lon2) {
			function deg2rad(deg) {
				return deg * (Math.PI / 180);
			}
			const R = 6371; // 地球半径，单位为公里
			const dLat = deg2rad(lat2 - lat1);
			const dLon = deg2rad(lon2 - lon1);

			const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
				Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) *
				Math.sin(dLon / 2) * Math.sin(dLon / 2);
			const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
			const distance = R * c;

			return distance;
		},
		addMark(lnglat) {
			const { map } = this
			const { markers, markConf, mode } = this
			if (mode !== "mark") return

			const mark = new AMap.Marker({
				clickable: true,
				...markConf.img[markConf.type](),

				position: new AMap.LngLat(lnglat.lng, lnglat.lat),
				map
			})
			this.i++

			const el = document.createElement("div")
			el.className = `n-map-markInfo`
			el.innerHTML = `
					<h3><input placeholder="请输入站点名称" class="n-map-nameInput" /><button class="n-map-changeName">修改名称</button><button class="n-map-clearBtn">清除</button></h3>
					<article>
						<input placeholder="进站压力 单位（MPa）" class="n-map-Input1"/>
						<input placeholder="压缩机组提供的压力 单位（MPa）" class="n-map-Input2"/>
            			<input placeholder="站内损失 单位（MPa）" class="n-map-Input3"/>
						<button  class="n-map-Btn">计算</button>
					</article>
					<br style="height: 1em;">
					<p>出站压力: <span class="n-map-Output1"></span> MPa</p>
					<br style="height: 1em;">
          			<p>压比为：<span class="n-map-Output2"></span></p>
					<br style="height: 1em;">
          			<p>压缩机功率(MW)：<span class="n-map-Output3"></span></p>
					<footer>经纬度：${lnglat.lat}, ${lnglat.lng}</footer>
				`

			// 监听父级点击
			el.onclick = ({ target: tg }) => {
				const { className } = tg
				console.log(className)
				// 清除
				if (className === "n-map-clearBtn") {
					const idx = markers.indexOf(mark)
					if (idx >= 0) markers.splice(idx, 1)
					mark.remove()
					mark._isDel = 1
					// 更新路径
					this.lines.forEach((l) => l.updateMark())
					this.infoWin.close()
				}

				// 修改节点名称
				if (className === "n-map-changeName") {
					const val = el.querySelector(".n-map-nameInput").value;
					mark.setLabel(val ? { content: val, direction: 'bottom' } : null)
				}

				// 出站压力计算
				if (className === "n-map-Btn") {
					const num1 = el.querySelector(".n-map-Input1").value - 0
					const num2 = el.querySelector(".n-map-Input2").value - 0
					const num3 = el.querySelector(".n-map-Input3").value - 0
					const num4 = num1 + num2 - num3
					el.querySelector(".n-map-Output1").innerText = num4.toFixed(3)
					const num5 = num4 / num1
					el.querySelector(".n-map-Output2").innerText = num5.toFixed(2)
					const G = this.params.a * 100000000 / (this.params.b * 24 * 3600) * 1.29 * this.params.h;
					const H = 1.4 / 0.4 * this.params.i * 478.38 * this.params.g * ((Math.pow(num5, (0.4 / 1.4))) - 1) / 1000000;
					const num6 = (G * H / this.params.n1);
					el.querySelector(".n-map-Output3").innerText = num6.toFixed(2)
				}
			}

			mark.infoEl = el
			markers.push(mark)

			// 拖拽的时候更新路径
			mark.on("dragging", () => this.lines.forEach((l) => l.update()))

			mark.on("click", (e) => {
				let { mode, curLine, infoWin, lines } = this
				// 默认模式下点击mark
				if (mode === "def") {
					infoWin.setContent(mark.infoEl)
					infoWin.open(map, mark.getPosition())
				}

				// 连线模式
				if (mode === "line") {
					if (!curLine) {
						curLine = this.curLine = {
							id: new Date().getTime(),
							marks: [mark],
							// 线条宽度  颜色  线条路径
							line: new AMap.Polyline({
								strokeWeight: 6,
								strokeColor: "#4095ff",
								path: [mark.getPosition()]
							}),
							// 更新路径
							update() {
								curLine.line.setPath(curLine.marks.map((v) => v.getPosition()))
							},
							// 如果标记删除了，更新标记数组
							updateMark() {
								curLine.marks = curLine.marks.filter((v) => !v._isDel)

								// 如果只剩下一个点或则没点了则删除
								if (curLine.marks.length <= 1) curLine.del()
								else curLine.update()
							},
							// 删除路径
							del() {
								map.remove(curLine.line)
								const idx = lines.indexOf(curLine)
								if (idx >= 0) lines.splice(idx, 1)
								if (this.curLine === curLine) this.curLine = null
							}
						}

						// 线的窗口，写法和mark一样的，原理都一样
						//我的id:${curLine.id}
						const el = document.createElement("div")
						el.className = `n-map-markInfo`
						el.innerHTML = `
								<h3>管道线路 <button class="n-map-clearBtn">清除</button></h3>
								<article>
									<input placeholder="起点压力 单位（MPa）" class="n-map-Input1" />
                  					<input placeholder="地温 单位（K）" class="n-map-Input2" />
                  					<input placeholder="管段传热系数 单位（W/m²·K）" class="n-map-Input3" />
                  					<button class="n-map-Btn2">计算</button>
								</article>
					<br style="height: 1em;">
                	<p>距离: <span class="n-map-disnum"></span> 千米</p>
					<br style="height: 1em;">
	              	<p>终点压力: <span class="n-map-Output1"></span> MPa</p>
					<br style="height: 1em;">
                	<p>终点温度：<span class="n-map-Output2"></span> K</p>
					<br style="height: 1em;">
                	<p>平均压力：<span class="n-map-Output3"></span> MPa</p>
					<br style="height: 1em;">
                	<p>平均温度：<span class="n-map-Output4"></span> K</p>
                	`
						// <footer>线段点个数：${curLine.marks.length}</footer>
						el.onclick = ({ target: tg }) => {
							// 利用class判断点击的元素
							const { className } = tg
							// 清除
							if (className === "n-map-clearBtn") {
								curLine.del()
								this.infoWin.close()
							}

							if (className === "n-map-Btn2") {
								const num1 = el.querySelector(".n-map-Input1").value - 0
								const num2 = el.querySelector('.n-map-disnum').innerText - 0
								const C0 = (this.params.m * this.params.i * this.params.g * this.params.h) / (Math.pow(0.03848, 2) * Math.pow(this.params.d - this.params.e, 5))
								const num4 = this.params.a * Math.pow(10, 8) / (this.params.b * 24 * 3600)
								const num5 = (Math.sqrt((Math.pow(num1 * 1000000, 2)) - C0 * num2 * 1000 * Math.pow(num4, 2))) / 1000000
								el.querySelector(".n-map-Output1").innerText = num5.toFixed(3)
								const num6 = el.querySelector(".n-map-Input2").value - 0
								const num7 = el.querySelector(".n-map-Input3").value - 0
								const a = (num7 * 3.14 * this.params.d) / (2156 * (this.params.a * 100000000 / (this.params.b * 24 * 3600) * 1.29 * this.params.h))
								const num8 = num6 + (this.params.a2 - num6) * Math.exp(-a * num2 * 1000)
								el.querySelector(".n-map-Output2").innerText = num8.toFixed(2)
								const num9 = (2 / 3) * (num1 + Math.pow(num5, 2) / (num1 + num5));
								el.querySelector(".n-map-Output3").innerText = num9.toFixed(3)
								const num10 = this.params.a2 / 3 + 2 * num8 / 3
								el.querySelector(".n-map-Output4").innerText = num10.toFixed(3)
							}
						}
						curLine.infoEl = el

						lines.push(curLine)
						map.add(curLine.line)
						// 点击线段触发
						curLine.line.on("click", async e => {
							if (this.mode !== "def" || !curLine.marks[0]) return
							console.log(e.lnglat, curLine.marks)

							// 取出最近的2点
							let disArr = curLine.marks.map(v => ({
								dis: this.getDis(e.lnglat.lat, e.lnglat.lng, v.getPosition().lat, v.getPosition().lng),
								item: v
							}))
							disArr = disArr.sort((a, b) => a.dis - b.dis).map(v => v.item);

							// 计算2点的距离
							const [a, b] = disArr;
							el.querySelector('.n-map-disnum').innerText = this.getDis(a.getPosition().lat, a.getPosition().lng, b.getPosition().lat, b.getPosition().lng).toFixed(2);
							infoWin.setContent(curLine.infoEl)
							infoWin.open(map, e.lnglat)
						})
						return
					}

					//过滤重复的标记
					if (curLine.marks.includes(mark)) return
					curLine.marks.push(mark)
					curLine.update()
					// 限制最多连2个点，超过2个点，距离计算会失真
					if (curLine.marks.length >= 2) this.curLine = null
				}
			})

			return mark
		},

		async initMap() {
			const AMap = await AMapLoader.load({
				key: "f53cbb7be64aec68afc88920d9b5fa39", //此处填入我们注册账号后获取的Key
				version: "2.0", //指定要加载的 JSAPI 的版本，缺省时默认为 1.4.15
				plugins: [
					"AMap.Scale",
					"AMap.ToolBar",
					"AMap.ControlBar",
					"AMap.MouseTool",
					"AMap.MapType",
					"AMap.HawkEye",
					"AMap.AutoComplete",
					"AMap.PlaceSearch"
				] //需要使用的的插件列表，如比例尺'AMap.Scale'等
			}).catch((e) => console.log(e))

			if (!AMap) return

			this.map = new AMap.Map("container", {
				//设置地图容器id
				viewMode: "3D", //是否为3D地图模式
				zoom: 10, //初始化地图级别
				center: [116.397428, 39.90923], //初始化地图中心点位置
				resizeEnable: true
			})

			this.map.addControl(new AMap.Scale()) // 添加左下角的比例尺
			const toolBar = new AMap.ToolBar({
				position: {
					bottom: "210px",
					right: "35px"
				}
			})
			const controlBar = new AMap.ControlBar({
				position: {
					bottom: "280px",
					right: "10px"
				}
			})
			this.map.addControl(toolBar) // 添加右下角的放大缩小
			this.map.addControl(controlBar) // 方向盘
			this.map.addControl(new AMap.MapType()) // 添加右上角的标准图和卫星图和路况
			this.map.addControl(new AMap.HawkEye()) // 添加地图放大镜
			this.infoWin = new AMap.InfoWindow({
				offset: new AMap.Pixel(0, -30)
			})

			this.bindEv()
		},

		searchfix(event) {
			this.handleClick(event)
			const {
				latitude: lat,
				longitude: lng
			} = this
			if (!lat || !lng) return
			this.mode = "mark"
			const mark = this.addMark({
				lat,
				lng
			})
			if (!mark) return
			this.mode = "def"
			mark.emit("click", {
				target: mark
			})

		},
		handleClickAndShow(event) {
			this.listConf.show = true;
			this.handleClick(event);
		},
		show(event) {
			this.handleClick(event)
		},
		add() {
			const newData = {
				username: this.$store.state.userInfo.username,
				name: '新的项目',
				// 其他字段可以省略，或者根据需要设置为空字符串或null  
				// 在这个例子中，我们省略了其他字段，因为它们不是必需的  
			};

			this.$request.post("/computed", newData).then(res => {
				if (res) { // 假设后端响应包含一个success字段来表示操作是否成功  
					this.$message.success("保存成功");
				} else {
					this.$message.error("保存失败");
				}
			}).catch(error => {
				console.error(error); // 输出错误信息到控制台，便于调试  
				this.$message.error("保存过程中发生错误");
			});
			location.reload();
		},
		del(item, idx) {
			if (this.params.id === item.id) this.params = {};
			const id = item.id
			this.$request.delete("/computed/" + id).then(res => {
				if (res) {
					this.$message.success("删除成功")
				} else {
					this.$message.error("删除失败")
				}
			})
			location.reload();
		},
		save(event) {
			this.handleClick(event)
			if (!this.isCheck()) return;
			const { listConf: { list }, params } = this;
			const idx = list.findIndex(v => v.id === params.id);
			if (!~idx) return;
			list.splice(idx, 1, JSON.parse(JSON.stringify(params)))
			this.$request.post("/computed", this.params).then(res => {
				if (res) {
					this.$message.success("保存成功")
				} else {
					this.$message.error("保存失败")
				}
			})
			location.reload();
		},
		exitsave() {
			if (!this.isCheck1()) return;
			const { listConf: { list }, params } = this;
			const idx = list.findIndex(v => v.id === params.id);
			if (!~idx) return;
			list.splice(idx, 1, JSON.parse(JSON.stringify(params)))
			this.$request.post("/computed", this.params).then(res => {
				if (res) {
					this.$message.success("保存成功")
				} else {
					this.$message.error("保存失败")
				}
			})
		},

		search(event) {
			this.handleClick(event)
			const {
				latitude,
				longitude
			} = this
			// 把每个经纬度减去当前输入的经纬度,然后求绝对值相加,在从小到大排序,数组第一个就是离当前输入点最近的点,在判断他的差值,如果大于10,则不算,否则打开这个点的弹窗
			const tg = this.markers
				.map((v) => ({
					num: Math.abs(v._position.lat - latitude) + Math.abs(v._position.lng - longitude),
					mark: v
				}))
				.sort((a, b) => a.num - b.num)[0]
			// 计算最近的点
			if (tg && tg.num < 10) {
				this.mode = "def"
				tg.mark.emit("click", {
					target: tg.mark
				})
			}
		},
		handleClickAndClear(event, keysToClear) {
			// 先执行 handleClick 的逻辑  

			let target = event.target;
			if (target.nodeName == "I" || target.nodeName == "SPAN") {
				target = event.target.parentNode;
			}
			target.blur();

			// 然后执行 clear 的逻辑来清空参数  
			this.clear(keysToClear);

			// 可以在这里继续添加其他操作  
		},
		check(item) {
			this.listConf.show = false;
			this.params = JSON.parse(JSON.stringify(item))
		},
		clear(keys) {
			keys.forEach(k => {
				this.params[k] = '';
			});
		},
		isCheck() {
			if (!this.params.id) return (this.$message.error('请选择项目'), 0)
			return true;
		},

		isCheck1() {
			if (!this.params.id) return
			return true;
		},
		isNull(v) {
			return ['', null, undefined].includes(v);
		},
		handleClick(event) {
			// 点击后鼠标移开恢复按钮默认样式(如果按钮没有加icon图标的话，target.nodeName == "I"可以去掉)
			let target = event.target;
			if (target.nodeName == "I" || target.nodeName == "SPAN") {
				target = event.target.parentNode;
			}
			target.blur();
			//进行其他操作
		},
	}
}
</script>


<style lang="scss">
.pmenu {
	width: 100%;
	height: 100%;
	overflow: hidden;
	padding: 0;
	position: relative;

	&,
	* {
		box-sizing: border-box;
	}
}

#container {
	width: 100%;
	height: 100%;
}

.n-dialog {
	position: absolute;
	right: 0;
	width: 400px;
	max-width: 70vw;
	z-index: 1000;
	top: 0;
	height: 100%;

	transition: all 0.3s;
	transform: translate(100%);

	&.n-dialogShow {
		transform: translate(0);
	}

	.n-dialog-switch {
		position: absolute;
		right: 100%;
		top: 20%;
		width: 50px;
		height: 50px;
		border-radius: 5px 0 0 5px;
		background: #fff;
		display: flex;
		align-items: center;
		justify-content: center;
		font-size: 24px;
		color: #777;
		cursor: pointer;

		&:hover {
			color: #4095ff;
		}
	}

	.n-dialog-content {
		width: 100%;
		padding: 15px;
		background: #fff;
		height: 100%;
		overflow-y: auto;
		overflow-x: hidden;

		>h3 {
			height: 40px;
			display: flex;
			align-items: center;
			justify-content: flex-start;
			font-size: 16px;
			color: #333;
		}

		.n-form {
			>p {
				font-size: 13px;
				color: #666;
				margin-bottom: 5px;

				&+* {
					margin-bottom: 20px;
				}
			}
		}
	}

}


.n-map-markInfo {
	padding: 10px 5px;
	font-size: 14px;
	color: #555;
	width: 300px;

	&,
	* {
		box-sizing: border-box;
	}

	>h3 {
		font-size: 16px;
		color: #333;
		font-weight: 400;
		display: flex;
		justify-content: space-between;
		align-items: center;
		margin-bottom: 20px;
		gap: 10px;

		>input {
			flex: 1;
			width: 100%;
		}

		>button {
			flex-shrink: 0;
		}
	}

	>article {
		display: flex;
		align-items: center;
		flex-wrap: wrap;
		align-content: flex-start;
		gap: 10px;
	}

	>footer {
		margin-top: 10px;
	}

	input {
		flex: 1;
		height: 30px;
		padding: 0 15px;
		color: #555;
		font-size: 13px;
		border-radius: 3px;
		border: 1px solid #ddd;
		outline: none;
	}

	button {
		height: 30px;
		padding: 0 15px;
		border-radius: 3px;
		color: #fff;
		display: inline-flex;
		border: 0;
		outline: none;
		align-items: center;
		justify-content: center;
		background: #4095ff;
		font-size: 13px;
	}
}

.amap-logo {
	display: none; //去掉高德地图logo
	opacity: 0 !important;
}

.amap-copyright {
	opacity: 0; //去掉高德的版本号
}

.pcomputed-dialog {
	>h3 {
		@include n-row1;
		justify-content: flex-end;
	}

	>ul {
		margin-top: 20px;

		>li {
			@include n-row1;
			gap: 10px;
			font-size: 14px;
			color: #555;
			border-bottom: 1px solid #eee;
			height: 40px;

			>i {
				color: #999;
			}

			.el-button {
				margin-left: auto;

				&+.el-button {
					margin-left: 0;
				}
			}
		}
	}
}
</style>
